/*
 * @Author       : Shandong Xiedali
 * @Mail     : 9727005@qq.com
 * @Date     : 2025/1/30 08:00:15
 * @FilePath     : curry.ts
 * @Description  :
 * Copyright (c) 2025 by Hiland & RainyTop, All Rights Reserved.
 */

/**
 * 偏函数化函数
 * @param fn 待偏函数化的函数(因为curry被递归调用的原因，fn的返回值类型为只能设为any类型，而不能设为泛型)
 * @param {T[]} args 初始参数列表
 * @returns  偏函数化后的函数，或者全函数的返回值
 * @example
 *     const add = (a: number, b: number, c: number) => a + b + c;
 *     const curriedAdd = curry(add);
 *
 *     const add1 = curriedAdd(1);
 *     const add12 = add1(2);
 *     const result = add12(3);
 *     expect(result).toBe(6);
 *
 *     const result2 = curriedAdd(2)(3)(4);
 *     expect(result2).toBe(9);
 *
 *     const result3 = curriedAdd(2, 3)(4);
 *     expect(result3).toBe(9);
 */
export function curry<T>(fn: (...args: T[]) => any, ...args: T[]) {
    // fn需要的参数个数
    const needCount: number = fn.length

    // 如果开始已经接收的参数个数已经大于等于需要的参数个数，
    // 就直接调用原函数（不再进行偏函数化了），否则返回一个新的函数接收剩余参数
    if (args.length >= needCount) {
        return fn(...args);
    }

    // 返回一个函数接收剩余参数
    return function (...params: T[]) {
        // 拼接已经接收和新接收的参数列表
        let allArgs: T[] = [...args, ...params];

        // 如果已经接收的参数个数还不够，继续返回一个新函数接收剩余参数
        if (allArgs.length < needCount) {
            return curry(fn, ...allArgs);
        }

        // 参数全部接收完调用原函数
        return fn(...allArgs);
    }
}
